CLIP¶

Contrastive Language-lmage Pre-Training(利用文本的监督信号训练一个迁移能力强的视觉模型)

解决问题:如何把图像和文本放在一起。

论文¶

Learning Transferable Visual Models from Natural Language Supervision

传统:

训练1000个类别,预测就只能限制于这1000个类别,无法扩展。

新增类别还要重新训练、重新标准。——重复工作、拓展能力(泛化能力、迁移能力)差

CLIP:预训练模型直接zreo-shot——给提示就能完成任务

CLIP论文指出:以前的方法不是不行,是资源不到位。——更大的模型、数据。

成名一战:

CLIP在完全不使用ImageNet中所有数据训练的前提下:

  • 直接Zero-shot得到的结果与Resnet在128WImagenet数据训练后效果一样

  • 使用4亿个配对的数据和文本来进行训练,直接爬取的,不标注

  • 现在CLIP下游任务已经很多了,GAN,检测,分割,检索等

如何训练模型:对比学习¶

image.png

不做预测,做对比。

对比学习:

正样本:图像和样本配对,就是正样本对;(上图矩阵对角线)

负样本:图像和样本不配对,图是狗,文本是树;

希望正样本相似度越大越好:让对角线相似度最大。

训练策略¶

image.png

image.png

对比学习效率比预测提高4倍。

合理运用prompt提示。

image.png

CLIP在MINIST数据集效果不好,只有89%:因为MINIST是人工合成的,不属于实际场景。

可见,clip比较适合实际常见场景。(zero-shot)

如何推理¶

image.png

提示:把类别扩展成一句话

CLIP的局限¶

跟Resnet50当成平手,但是Resnet50也不是标杆

OpenAi说如果要跟标杆(比如ViT)比较,数据集需要1000X(扩大1000倍)

只能面向常规的,Mnist它效果一般,因为这种数据是人工合成的

面向测试集调参?就跟lmagenet干上了,参数都适合imagenet

代码:CLIP包¶

In [ ]:
import torch
import clip
from PIL import Image

# Load the pre-trained CLIP model
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device) # 保留路径:C:\Users\HP\.cache\clip
In [ ]:
# Load image
image_path = "F:\FNii\VLM\image.png"
image = Image.open(image_path)

# Define your input image and text
image = preprocess(image).unsqueeze(0)  # Preprocess your image
text = clip.tokenize(["city","people","park"])  # Tokenize your text,必须是向量

# Encode the image and text
with torch.no_grad():
    image_features = model.encode_image(image.to(device))
    text_features = model.encode_text(text.to(device))

# Perform similarity calculation
similarity = (100.0 * image_features @ text_features.T).softmax(dim=-1)

# Print the similarity scores
print(similarity)
In [ ]:
# unsqueeze(0):在维度0上增加一个维度

# unsqueeze()函数是在张量(Tensor)上操作的方法,它的作用是在指定的维度上增加一个维度。在这里,unsqueeze(0)表示在维度0上增加一个维度。

# 举个例子来说明,假设有一个形状为(3,)的一维张量,即一个包含3个元素的向量。调用unsqueeze(0)后,这个张量的形状将变为(1, 3),即一个包含1行3列的二维张量。

# 这个函数在某些情况下非常有用,例如在进行某些运算时需要保持张量的维度一致,或者在将一维张量作为输入传递给某些需要二维张量的函数时。

# 需要注意的是,unsqueeze()函数返回的是一个新的张量,原始张量并没有被修改。因此,在使用unsqueeze()函数后,需要将返回的新张量赋值给一个变量或者使用它进行后续的操作。
In [ ]:
image_path = "F:\FNii\VLM\image.png"
image = Image.open(image_path)

pre_image = preprocess(image)
pre_image.shape
In [ ]:
pre_image.unsqueeze(0).shape

代码:Huggingface¶

In [ ]:
from PIL import Image
from transformers import CLIPProcessor,CLIPModel 
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")#openai/clip-vit-base-patch32
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
preprocessor_config.json:   0%|          | 0.00/316 [00:00<?, ?B/s]
tokenizer_config.json:   0%|          | 0.00/592 [00:00<?, ?B/s]
vocab.json:   0%|          | 0.00/862k [00:00<?, ?B/s]
merges.txt:   0%|          | 0.00/525k [00:00<?, ?B/s]
tokenizer.json:   0%|          | 0.00/2.22M [00:00<?, ?B/s]
special_tokens_map.json:   0%|          | 0.00/389 [00:00<?, ?B/s]
In [ ]:
import requests
url = "http://images.cocodataset.org/val2017/000000039769.jpg"
image = Image.open(requests.get(url, stream=True).raw)
image
Out[ ]:
In [ ]:
# image = Image.open('F:\FNii\VLM\image.png')
text =['dog','cat','tiger'] # 必须英文
inputs = processor(text=text, images=image, return_tensors="pt", padding=True)
outputs = model(**inputs)
logits_per_image =outputs.logits_per_image# this is the image-text similarity score
logits_per_image # tensor([[18.2806, 23.2766, 21.0254]], grad_fn=<TBackward0>)
In [ ]:
probs = logits_per_image.softmax(dim=1)# we can take the softmax to get the label probabilities
for i in range(len(text)):
    print(text[i],':',probs[0][i])
dog : tensor(0.0061, grad_fn=<SelectBackward0>)
cat : tensor(0.8993, grad_fn=<SelectBackward0>)
tiger : tensor(0.0947, grad_fn=<SelectBackward0>)

DALL-E¶

从文本生成图片

image.png

VQGAN¶

image.png

In [ ]: